package com.zwcl.payment.gateway.channel;

import com.zwcl.payment.gateway.config.WeixinMchConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.net.ssl.SSLContext;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description HttpClient客户端工厂
 * @Author guobaikun
 * @Date 2019/11/8 10:40
 * @Email kunye.guo@wetax.com.cn
 */
@Component
@Slf4j
public class HttpClientFactory {

    //@Autowired
    //private WarnService warnService;
    @Autowired
    private WeixinMchConfig weixinMchConfig;

    private static Map<String, CloseableHttpClient> httpClientContainer;//TODO 用ConcurrentHashMap处理

    static {
        httpClientContainer = new HashMap();
    }

    /**
     * @Description 初始所有类型的httpClient客户端
     */
    @PostConstruct
    public void init(){
        log.info("开始初始化所有类型的httpClient客户端");
        //实例化无证书
        try {
            httpClientContainer.put("0", instanceHttpClient("0", null));
        } catch (Exception e) {
            String title = "httpClient_0实例化失败";
            log.error(title, e);
            //warnService.warnFromException(e, title);
        }
        //实例化有证书
        for (Map.Entry<String, String> entry : weixinMchConfig.getCertificate().entrySet()) {
            try {
                httpClientContainer.put(entry.getKey(), instanceHttpClient(entry.getKey(), entry.getValue()));
            } catch (Exception e) {
                String title = "httpClient_"+entry.getKey()+"实例化失败";
                log.error(title, e);
                //warnService.warnFromException(e, title);
            }
        }
    }

    /**
     * 获取httpClient
     * @param mchId 商户号，若传null，则返回无证书httpClient
     * @return
     */
    public static CloseableHttpClient getInstance(String mchId){
        if(StringUtils.isBlank(mchId)) mchId="0";
        return httpClientContainer.get(mchId);
    }

    /**
     * 获取httpClient
     * @return
     */
    public static CloseableHttpClient getInstance(){
        return getInstance("0");
    }

    /**
     * 根据商户实例化httpClient
     * @param mchId 商户号
     * @param certificatePath 证书路径
     * @return
     */
    private CloseableHttpClient instanceHttpClient(String mchId, String certificatePath) throws Exception {
        SSLConnectionSocketFactory sslsf;
        if(mchId.equals("0")){
            sslsf = SSLConnectionSocketFactory.getSystemSocketFactory();
        }else{
            KeyStore keyStore  = KeyStore.getInstance("PKCS12");
            keyStore.load(this.getClass().getResourceAsStream(certificatePath), mchId.toCharArray());
            SSLContext sslcontext = SSLContexts.custom()
                    .loadKeyMaterial(keyStore, mchId.toCharArray())
                    .build();
            sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[] { "TLSv1" },
                    null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        }

        PoolingHttpClientConnectionManager phccm = new PoolingHttpClientConnectionManager(
                RegistryBuilder.<ConnectionSocketFactory>create()
                        .register("http", PlainConnectionSocketFactory.getSocketFactory())
                        .register("https", sslsf)
                        .build());
        phccm.setMaxTotal(400);
        phccm.setDefaultMaxPerRoute(200);
        phccm.setValidateAfterInactivity(5000);
        RequestConfig rc = RequestConfig.custom()
                .setConnectionRequestTimeout(2000)
                .setConnectTimeout(2000)
                .setSocketTimeout(5000)
                .build();
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(phccm)
                .setDefaultRequestConfig(rc)
                .evictIdleConnections(60, TimeUnit.SECONDS)
                .evictExpiredConnections()
                .build();
        return httpClient;
    }

}
